#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#define MAX 1024        // 命令字符串最大长度
#define ARGC 64         // 参数数组最大容量
#define SEP " "         // 参数分隔符

// 定义重定向类型枚举
enum redir {
    REDIR_INPUT = 0,    // 输入重定向（未实现）
    REDIR_OUTPUT,       // 输出重定向（覆盖）
    REDIR_APPEND,       // 输出重定向（追加）
    REDIR_NONE          // 无重定向
};

typedef enum redir redir;

// 检查命令字符串中的重定向符号并提取文件名
char* checkDir(char commandstr[], redir* redir_type) {
    char* filename = NULL;
    while (*commandstr != '\0') {
        if (*commandstr == '>') {               // 检测输出重定向符号
            *commandstr++ = '\0';               // 截断命令字符串
            *redir_type = REDIR_OUTPUT;         // 默认设置为覆盖模式
            if (*commandstr == '>') {           // 检测追加符号 >>
                *commandstr++ = '\0';
                *redir_type = REDIR_APPEND;     // 设置为追加模式
            }
            while (isspace(*commandstr))        // 跳过空格
                commandstr++;
            filename = commandstr;              // 获取文件名起始位置
            while (!isspace(*commandstr) && *commandstr != '\0')
                commandstr++;
            *commandstr = '\0';                 // 截断文件名
            return filename;
        } else {
            commandstr++;
        }
    }
    return NULL; // 无重定向
}

// 分割命令字符串为参数数组
int split(char* commandstr, char* argv[]) {
    assert(commandstr && argv);
    argv[0] = strtok(commandstr, SEP);          // 首次分割
    if (argv[0] == NULL) return -1;             // 空命令
    int i = 1;
    while ((argv[i++] = strtok(NULL, SEP)));    // 继续分割剩余部分
    return 0;
}

// 调试用：打印参数数组
void debugPrint(char* argv[]) {
    for (int i = 0; argv[i]; ++i)
        printf("%d:%s\n", i, argv[i]);
}

// 显示所有环境变量
void showEnv() {
    extern char** environ;                      // 系统环境变量
    for (int i = 0; environ[i]; ++i)
        printf("%d:%s\n", i, environ[i]);
}

int main() {
    int last_exit = 0;                          // 记录上一个命令的退出状态
    char myenv[32][256];                        // 存储用户定义的环境变量
    int env_index = 0;                          // 环境变量数组索引

    while (1) {
        redir redir_type = REDIR_NONE;
        char commandstr[MAX] = {0};             // 存储输入的命令
        char* argv[ARGC] = {NULL};              // 参数数组

        // 打印提示符并读取输入
        printf("[lgr@mymachine currpath]# ");
        fflush(stdout);
        fgets(commandstr, sizeof(commandstr), stdin);
        commandstr[strlen(commandstr)-1] = '\0'; // 去掉换行符

        // 处理重定向符号
        char* filename = checkDir(commandstr, &redir_type);

        // 分割命令参数
        if (split(commandstr, argv) != 0) continue;

        /* ------------ 内建命令处理 ------------ */
        if (strcmp(argv[0], "cd") == 0) {       // 切换目录
            if (argv[1]) chdir(argv[1]);
            continue;
        } else if (strcmp(argv[0], "export") == 0) { // 设置环境变量
            if (argv[1]) {
                strcpy(myenv[env_index], argv[1]);
                putenv(myenv[env_index++]);     // 添加到系统环境
            }
            continue;
        } else if (strcmp(argv[0], "env") == 0) { // 显示环境变量
            showEnv();
            continue;
        } else if (strcmp(argv[0], "echo") == 0) { // 处理echo命令
            if (argv[1] && argv[1][0] == '$') {
                if (argv[1][1] == '?') {        // 特殊变量 $?
                    printf("%d\n", last_exit);
                } else {                        // 用户定义变量
                    char* val = getenv(argv[1]+1);
                    if (val) printf("%s=%s\n", argv[1]+1, val);
                }
            }
            continue;
        }

        // 为ls命令添加--color=auto参数（美化输出）
        if (strcmp(argv[0], "ls") == 0) {
            int pos = 0;
            while (argv[pos]) pos++;            // 找到参数数组末尾
            argv[pos++] = "--color=auto";       // 添加参数
            argv[pos] = NULL;
        }

        /* ------------ 外部命令执行 ------------ */
        pid_t id = fork();
        if (id == 0) {                          // 子进程
            if (redir_type != REDIR_NONE) {     // 处理输出重定向
                int flags = O_WRONLY | O_CREAT;
                flags |= (redir_type == REDIR_APPEND) ? O_APPEND : O_TRUNC;
                int fd = open(filename, flags, 0666);
                dup2(fd, STDOUT_FILENO);        // 重定向标准输出到文件
                close(fd);
            }
            execvp(argv[0], argv);              // 执行命令
            exit(1);                            // exec失败时退出
        }

        // 父进程等待子进程结束
        int status;
        waitpid(id, &status, 0);
        last_exit = WEXITSTATUS(status);        // 记录退出状态
    }
    return 0;
}